package com.offcn.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Author: zola
 * @Date: 2021/9/17 - 09 - 17 - 0:07
 * @Description: com.offcn.gateway.filter
 * @Version: 1.0
 */
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 获取request、response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 2. 获取请求路径：用户登录、注册是不需要鉴权，直接放行
        String path = request.getURI().getPath();
        System.out.println(path);  // /api/user/login
        // 3. 对请求路径进行判断，如果获取的路径与登录和注册匹配，直接放行
        if (path.equals("/api/user/login") || path.equals("/api/user/regist")) {
           return chain.filter(exchange);
        }
        // 4. 获取jwt:从请求头、请求参数、session中获取
        // 7. 将所有的token都添加到请求头中
        boolean headerHasToken = true;
        String token = request.getHeaders().getFirst("Authorization");
        if (StringUtils.isEmpty(token)) {
            token = request.getQueryParams().getFirst("Authorization");
            headerHasToken = false;
        }
        if (StringUtils.isEmpty(token)) {
            // 3.从cookie中获取
            if(request.getCookies().getFirst("Authorization") != null) {
                token = request.getCookies().getFirst("Authorization").getValue();
                headerHasToken = false;
            }
        }
        // 5. 如果获取的token是空，直接拦截
        if (StringUtils.isEmpty(token)) {
            response.setStatusCode(HttpStatus.SEE_OTHER); //303 表示重定向
            response.getHeaders().set("Location","http://localhost:9999/oauth/login");
            return response.setComplete();
        }
        // 6. 将token与jwt做验证
        try {
            /*JwtUtil.parseJwt(token);
            if(!headerHasToken){
                request.mutate().header("Authorization",token);
            }*/
            /*
            不再是用jwt来做验证，而是在微服务中使用公钥来做验证
            不管是从项目定义的登录方式，还是认证中心定义的第三方登录方式，微服务做验证都是以
            “Authorization” : “bearer token”的形式，而不是“Authorization” : “token”的形式

            所以对于用户自身的登录===>token肯定不是以“bearer ”开头，它继续只做token是否为空的校验，即是否登录
            但是对于第三登录 ===>token是从认证中心传来的，是使用密码模式的私钥进行加密的，而且访问必须是“bearer ”开头
            如果不是以其开头，都加入以“bearer ”开头，从而实先了俩种结果
            1.用户自身的登录：加上了其开头，依就是验证token是否为空的校验，其次它加上了，也肯定不能以这种方式去访问资源，因为其token不是认证中心的token
            2.第三客户端的登录：产生的token，不管是否以开头，都会生成一个新的"bearer token":当然也能够访问
            */
            if (!token.startsWith("bearer ")){
                token = "bearer " + token;
            }
            request.mutate().header("Authorization",token);
            return chain.filter(exchange);  // 放行
        } catch (Exception e) {
            e.printStackTrace();
            // 拦截
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
